Skip to content

Conversation

@piotrrzysko
Copy link
Member

@piotrrzysko piotrrzysko commented Nov 18, 2025

Description

This PR introduces a new optional clause for CREATE MATERIALIZED VIEW that allows users to control the behavior of materialized views when they are stale.

I will updated the documentation once the proposed syntax and behavior are approved.

New syntax

CREATE MATERIALIZED VIEW mv_name
WHEN STALE { FAIL | INLINE }
AS SELECT ...

Behavior

  • FAIL - If the MV is stale, queries referencing it will fail. Analysis of the underlying query is never performed while querying the MV.
  • INLINE (default) - Preserves the current behavior. Even if the MV is stale, it is expanded like a logical view, and the underlying query is analyzed.

Motivation

  • Avoid analyzing the underlying query every time, which can be costly when it references many tables.
  • Allow using fresh MVs even when some data sources are temporarily unavailable.

Additional context and related issues

Release notes

(x) This is not user-visible or is docs only, and no release notes are required.
( ) Release notes are required. Please propose a release note for me.
( ) Release notes are required, with the following suggested text:

TableHandle tableHandle = metadata.getTableHandle(session, storageTableName)
.orElseThrow(() -> semanticException(INVALID_VIEW, table, "Storage table '%s' does not exist", storageTableName));
return createScopeForMaterializedView(table, name, scope, materializedViewDefinition, Optional.of(tableHandle));
return createScopeForMaterializedView(table, name, scope, materializedViewDefinition, Optional.of(tableHandle), useLogicalViewSemantics);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit concerned about this line: the new clause affects the path for fresh MVs (WHEN STALE FAIL skips analysis, while WHEN STALE INLINE runs the analysis), even though the syntax suggests it should only define behavior for stale MVs.

Is analysis of the underlying query even necessary for fresh MVs, regardless of the WHEN STALE clause? I understand that it can detect schema changes in the base tables or changes to the MV definer’s access permissions - but is that the intended behavior?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand that it can detect schema changes in the base tables or changes to the MV definer’s access permissions - but is that the intended behavior?

i think that was intended behavior...

Is analysis of the underlying query even necessary for fresh MVs, regardless of the WHEN STALE clause?

... however i think it should be skipped. this would be significant benefit when MVs are used in low latency scenarios.
in fact, for an MV with 24h grace period that was refreshed with last day, we should skip this line during a SELECT query, because it doesn't matter

tableChangeInfoTasks.add(() -> getTableChangeInfo(session, tableToSnapShot));

let's file an issue for this and follow-up separately

@piotrrzysko piotrrzysko marked this pull request as ready for review November 18, 2025 10:15
@Praveen2112
Copy link
Member

What is our plan on changing this behaviour for existing or new MVs ?

}
// This is a stale materialized view and should be expanded like a logical view
return createScopeForMaterializedView(table, name, scope, materializedViewDefinition, Optional.empty());
return createScopeForMaterializedView(table, name, scope, materializedViewDefinition, Optional.empty(), useLogicalViewSemantics);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of passing a useLogicalViewSemantics can we create a scope for the storage table ?

@Praveen2112
Copy link
Member

Apart from the benefit on skipping the analysis what are the other benefits would I get if a run a query as WHEN STALE FAIL ? Now when I create a MV with WHEN STALE - I won't be able to use it unless I run a REFRESH MV. In case of pipeline which uses this MV might be affected if a MV went stale ? Is this expected ? Should we add this as an extension of WHEN FRESH SKIP ANALYSIS or something similar ?

@martint
Copy link
Member

martint commented Nov 18, 2025

For context, #15326

@martint
Copy link
Member

martint commented Nov 18, 2025

Also, #23387 (reply in thread) and #23747

@piotrrzysko
Copy link
Member Author

piotrrzysko commented Nov 19, 2025

@Praveen2112

What is our plan on changing this behaviour for existing or new MVs ?

This change is meant to be backward-compatible. The new clause is optional. If it is not specified, or if WHEN STALE INLINE is used, the MV will behave as it does currently.

Apart from the benefit on skipping the analysis what are the other benefits would I get if a run a query as WHEN STALE FAIL ? Now when I create a MV with WHEN STALE - I won't be able to use it unless I run a REFRESH MV. In case of pipeline which uses this MV might be affected if a MV went stale ? Is this expected ?

Skipping the analysis is not the goal in itself. The goal is to achieve better availability when the source tables are not available and to get closer to the semantics mentioned in the issues that Martin and I linked in this PR - specifically, that within the grace period, the MV should be treated as if it were a regular storage table. And today, as far as I know, the only blocker for this is the analysis performed every time the MV is queried.

Should we add this as an extension of WHEN FRESH SKIP ANALYSIS or something similar ?

This is more or less what I wanted to express in this comment: #27356 (comment). I’m happy to discuss what the syntax should look like to achieve the goals described above. Personally, WHEN FRESH SKIP ANALYSIS feels too low-level - as mentioned in my comment, I'd consider always skipping analysis when the MV is fresh.

@piotrrzysko
Copy link
Member Author

@martint just a gentle reminder about the PR when you have a moment

@findepi
Copy link
Member

findepi commented Nov 26, 2025

@piotrrzysko can you please rebase? there is a conflict.

Copy link
Member

@findepi findepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add WHEN STALE FAIL/INLINE syntax

lgtm

Copy link
Member

@findepi findepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add when stale behavior in ConnectorMaterializedViewDefinition

@findepi findepi changed the title Add WHEN STALE option to CREATE MATERIALIZED VIEW Add WHEN STALE option to CREATE MATERIALIZED VIEW and implement in Iceberg Nov 28, 2025
@findepi findepi changed the title Add WHEN STALE option to CREATE MATERIALIZED VIEW and implement in Iceberg Add WHEN STALE option to CREATE MATERIALIZED VIEW Nov 28, 2025
@findepi findepi changed the title Add WHEN STALE option to CREATE MATERIALIZED VIEW Add WHEN STALE syntax for CREATE MATERIALIZED VIEW Nov 28, 2025
@findepi findepi added no-release-notes This pull request does not require release notes entry and removed syntax-needs-review labels Dec 3, 2025
Copy link
Member

@findepi findepi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please rebase to resolve a conflict

Comment on lines 1482 to 1484
if (node.getWhenStaleBehavior().isPresent()) {
throw new TrinoException(NOT_SUPPORTED, "WHEN STALE is not supported yet");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether Add when stale behavior in ConnectorMaterializedViewDefinition commit should be removing those lines.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is needed to test whether MATERIALIZED_VIEW_WHEN_STALE_BEHAVIOR is respected, which happens during execution:

if (!plannerContext.getMetadata().getConnectorCapabilities(session, catalogHandle).contains(MATERIALIZED_VIEW_WHEN_STALE_BEHAVIOR)) {
throw semanticException(NOT_SUPPORTED, statement, "Catalog '%s' does not support WHEN STALE", catalogName);
}

One line below, I throw NOT_SUPPORTED even if a connector claims to support WHEN STALE:

throw semanticException(NOT_SUPPORTED, statement, "WHEN STALE is not supported yet");

This is a preparatory change that allows connectors to store information
about the WHEN STALE behavior. The option cannot yet be used in practice,
as execution will still fail with a NOT_SUPPORTED error.
@findepi findepi merged commit cfca263 into trinodb:master Dec 3, 2025
100 checks passed
@github-actions github-actions bot added this to the 479 milestone Dec 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed iceberg Iceberg connector lakehouse no-release-notes This pull request does not require release notes entry

Development

Successfully merging this pull request may close these issues.

4 participants